//
//  CaculatorBrain.swift
//  StanfordCaculator
//
//  Created by 黄睿 on 16/10/30.
//  Copyright © 2016年 ipaynow. All rights reserved.
//

import Foundation
// model进行数值计算
class CaculatorBrain{
    
    private var accumulator = 0.0
    
    func setOperand(operand:Double){
        accumulator = operand
    
    }
    
    private enum Operation{
        case Constant(Double)
        case UnaryOperation((Double) -> Double)
        case BinaryOpertaion((Double,Double) -> Double)
        case Equals
    }
    
    private var operation: Dictionary<String,Operation> = [
        "π" : Operation.Constant(M_PI),            //M_PI,
        "e" : Operation.Constant(M_E),            //M_E,
        "√" : Operation.UnaryOperation(sqrt),      //sqrt,
        "cos" : Operation.UnaryOperation(cos),
        "±" : Operation.UnaryOperation({ -$0 }),  //cos
        "×" : Operation.BinaryOpertaion({ $0 * $1 }),
        "÷" : Operation.BinaryOpertaion({ $0 / $1 }),
        "+" : Operation.BinaryOpertaion({ $0 + $1 }),
        "−" : Operation.BinaryOpertaion({ $0 - $1 }),
        "=" : Operation.Equals
    ]
    private func excutePendingBinaryOperation(){
        if pending != nil{
            accumulator = pending!.binaryFunction(pending!.firstOperand,accumulator)
            pending = nil
        }
    }
    
    func performOperation(symbol: String){
        if let operation = operation[symbol]{
            switch operation{
            case .Constant(let value):
                accumulator = value
            case .UnaryOperation(let function):
                accumulator = function(accumulator)
            case .BinaryOpertaion(let function):
                excutePendingBinaryOperation()
                pending = PendingBinaryPerationInfo(binaryFunction: function, firstOperand: accumulator)
            case .Equals :
                excutePendingBinaryOperation()
            }
        }
    }
    
    private var pending: PendingBinaryPerationInfo?
    
    private struct PendingBinaryPerationInfo {
        var binaryFunction: (Double, Double) -> Double
        var firstOperand: Double
    }
    
    var result: Double{
        get{
            return accumulator
        }
    }
    
    
    
    
}

